// 在 node.js 中实现事件监听和事件触发

// 采用 ES6 语法定义一个类(表示某种事物)
class EventEmitter {
    // 定义一个实例属性用以存储事件及其监听器
    events = {
    }
    // 绑定事件监听器
    on( type , handler ){
        // 首先尝试从 events 中获取 type 事件对应的监听器数组
        let handlers = this.events[ type ];
        // 若监听器数组存在
        if( handlers && Array.isArray( handlers ) ) {
            // 则将新的监听器添加到数组中
            handlers.push( handler );
            // 方法立即返回
            return ;
        }
        // 使用 属性表达式 为对象动态添加属性
        this.events[ type ] = [ handler ];
    }
    // 触发事件 (这里使用了是REST参数)
    emit( type , ...params){
        // 根据 type 获得相应的监听器数组
        let handlers = this.events[ type ];
        // 若 handlers 是数组，则遍历数组中的每个函数
        if( Array.isArray( handlers ) ) {
            // 遍历数组中的所有函数并通过 call 方式执行每个函数
            handlers.forEach( h => h.call( this , ...params ) ); // 这里的 ... 是展开运算符
        }
    }
    // 移除事件监听器
    off( type , handler ){
        // 根据 type 获得相应的监听器数组
        let handlers = this.events[ type ];
        // 若 handlers 是数组，则从数组中寻找与参数 handler 相同的 函数
        if( Array.isArray( handlers ) ) {
            if( handlers.length === 1 && handlers[0] === handler ) {
                // 直接从 events 对象中删除 type 对应的属性
                delete this.events[ type ];
                // 让当前函数立即返回
                return ;
            }
            // 根据 findIndex 的参数所指定的函数的返回值 寻找与 handler 相同的函数在数组中的索引
            let index = handlers.findIndex( h => h === handler );
            // 若 从 handlers 中找到 与 handler 相同的函数则直接将其移除
            if( index != -1 ) {
                // 删除 index 处的 单个元素
                handlers.splice( index , 1 );
            }
        }
    }
}

// 将 EventEmitter 导出
module.exports = EventEmitter ;
